package com.ww.exercise.coroutine.easy.q1

import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis

// 数据模型
data class ServiceData(val id: String, val content: String)
data class AggregatedData(val service1: ServiceData, val service2: ServiceData, val service3: ServiceData)

// 模拟三个服务调用（不同耗时）
suspend fun callService1(fail: Boolean = false): ServiceData {
    return try {
        println("Service1: 开始调用")
        delay(400) // 模拟400ms耗时
        if (fail) {
            throw RuntimeException("Service1主动失败")
        }
        /**
         * also函数的核心特性
         * also是Kotlin标准库中的扩展函数，属于"作用域函数"（Scope Function）家族，其完整签名如下：
         * ==============================================================================
         * inline fun <T> T.also(noinline crossinline action: (T) -> Unit): T
         * 它接收一个lambda表达式作为参数，该lambda接受当前对象作为参数，并返回原始对象本身。
         * ==============================================================================
         * 典型使用场景
         * 对象初始化后的操作
         * val result = ServiceData("S1", "服务1数据").also { println("Service1: 调用完成") // 可进行日志记录、参数校验等操作 }
         * 注意：also的lambda参数是隐式接收的，不能显式声明
         * 链式调用
         * val config = ConfigBuilder().also {     it.setTimeout(5000) }.build()
         */
        ServiceData("S1", "服务1数据").also {
            println("Service1: 调用完成")
        }
    } catch (e: CancellationException) {
        println("Service1: 被取消（因其他服务失败）")
        throw e
    }
}

suspend fun callService2(fail: Boolean = false): ServiceData {
    return try {
        println("Service2: 开始调用")
        delay(600) // 模拟600ms耗时
        if (fail) {
            throw RuntimeException("Service2主动失败")
        }
        ServiceData("S2", "服务2数据").also {
            println("Service2: 调用完成")
        }
    } catch (e: CancellationException) {
        println("Service2: 被取消（因其他服务失败）")
        throw e
    }
}

suspend fun callService3(fail: Boolean = false): ServiceData {
    return try {
        println("Service3: 开始调用")
        delay(500) // 模拟500ms耗时
        if (fail) {
            throw RuntimeException("Service3主动失败")
        }
        ServiceData("S3", "服务3数据").also {
            println("Service3: 调用完成")
        }
    } catch (e: CancellationException) {
        println("Service3: 被取消（因其他服务失败）")
        throw e
    }
}

// 并行执行：使用结构化并发，任一失败则整体失败
suspend fun parallelExecute(failService: Int? = null): AggregatedData = coroutineScope {
    println("\n=== 开始并行执行 ===")
    // 启动三个并行任务，可指定某个服务失败
    val s1 = async { callService1(failService == 1) }
    val s2 = async { callService2(failService == 2) }
    val s3 = async { callService3(failService == 3) }

    // 等待所有结果（任一失败会立即终止）
    AggregatedData(
        service1 = s1.await(),
        service2 = s2.await(),
        service3 = s3.await()
    ).also {
        println("=== 并行执行全部完成 ===")
    }
}

// 串行执行：依次调用，任一失败则终止
suspend fun serialExecute(failService: Int? = null): AggregatedData {
    println("\n=== 开始串行执行 ===")
    // 依次调用三个服务，可指定某个服务失败
    val s1 = callService1(failService == 1)
    val s2 = callService2(failService == 2)
    val s3 = callService3(failService == 3)

    return AggregatedData(s1, s2, s3).also {
        println("=== 串行执行全部完成 ===")
    }
}

fun main() = runBlocking {
    // 1. 测试正常情况（无失败）
    println("======= 正常场景测试 =======")
    val parallelNormalTime = measureTimeMillis {
        try {
            val result = parallelExecute()
            println("并行执行结果: $result")
        } catch (e: Exception) {
            println("并行执行异常: ${e.message}")
        }
    }
    val serialNormalTime = measureTimeMillis {
        try {
            val result = serialExecute()
            println("串行执行结果: $result")
        } catch (e: Exception) {
            println("串行执行异常: ${e.message}")
        }
    }
    println("\n正常场景耗时对比:")
    println("并行执行: $parallelNormalTime ms")
    println("串行执行: $serialNormalTime ms")
    println("并行节省时间: ${serialNormalTime - parallelNormalTime} ms")

    // 2. 测试异常情况（Service2失败）
    println("\n\n======= 异常场景测试（Service2失败） =======")
    val parallelErrorTime = measureTimeMillis {
        try {
            parallelExecute(failService = 2)
            println("并行执行成功（不应执行）")
        } catch (e: Exception) {
            println("并行执行异常捕获: ${e.message}")
        }
    }
    val serialErrorTime = measureTimeMillis {
        try {
            serialExecute(failService = 2)
            println("串行执行成功（不应执行）")
        } catch (e: Exception) {
            println("串行执行异常捕获: ${e.message}")
        }
    }
    println("\n异常场景耗时对比:")
    println("并行执行: $parallelErrorTime ms")
    println("串行执行: $serialErrorTime ms")
}

